<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        @import url(http://fonts.useso.com/css?family=Indie+Flower);
        body {
            font-family: 'Indie Flower', cursive;
            color: whitesmoke;
            fill: whitesmoke;
            background-color: #333;
        }
        .link {
            fill: none;
            stroke: gray;
            stroke-width: 1.5px;
        }
        #d3Frame {
            padding-left: 10px;
        }
    </style>
</head>
<body>
<h2>@EdgeThreeSixty - Services as a D3 Tree</h2>
<div id="d3Frame"></div>
<script src='http://d3js.org/d3.v3.min.js'></script>
<script src="../../js/jquery.js"></script>
</body>
</html>

<script>
    var taxonomyId = 'edc7ab14-3c02-83ed-8e58-5e1bf8c34fad';

    $.get('https://get-json.azurewebsites.net/api/v1/taxonomy/' + taxonomyId).done(function(data) {
        jsonToD3(exportTreeToJSON(data.taxonomy).children[0]);
    });

    // Helper functions
    function jsonToD3(data) {
        // taken from:
        // http://bl.ocks.org/mbostock/4063582
        // http://bl.ocks.org/mbostock/4339083
        var container = document.getElementById('d3Frame');
        while (container.firstChild) {
            container.removeChild(container.firstChild);
        }
        var margin = {
            top: 5,
            right: 120,
            bottom: 5,
            left: 120
        };
        var width = 960 - margin.right - margin.left;
        var height = 500 - margin.top - margin.bottom;
        var i = 0,
                duration = 500;
        var root = data;
        var tree = d3.layout.tree().size([height, width]);
        var diagonal = d3.svg.diagonal().projection(function(d) {
            return [d.y, d.x];
        });
        var svg = d3.select("#d3Frame").append("svg")
                .attr("width", '100%').attr("height", height + margin.top + margin.bottom).append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
        root.x0 = height / 2;
        root.y0 = 0;

        function collapse(d) {
            if (d.children) {
                d._children = d.children;
                d._children.forEach(collapse);
                d.children = null;
            }
        }

        root.children.forEach(collapse);
        update(root);
        d3.select('#d3Frame').style("height", "500px");

        function update(source) {
            // Compute the new tree layout.
            var nodes = tree.nodes(root).reverse(),
                    links = tree.links(nodes);

            // Normalize for fixed-depth.
            nodes.forEach(function(d) {
                d.y = d.depth * 180;
            });

            // Update the nodes…
            var node = svg.selectAll("g.node").data(nodes, function(d) {
                return d.id || (d.id = ++i);
            });

            // Enter any new nodes at the parent's previous position.
            var nodeEnter = node.enter().append("g").attr("class", "node").attr("transform", function(d) {
                return "translate(" + source.y0 + "," + source.x0 + ")";
            }).on("click", click);
            nodeEnter.append("circle").attr("r", 1e-6).style("fill", function(d) {
                return d._children ? "lightsteelblue" : "#fff";
            });
            nodeEnter.append("text").attr("x", function(d) {
                return d.children || d._children ? -10 : 10;
            }).attr("dy", ".35em").attr("text-anchor", function(d) {
                return d.children || d._children ? "end" : "start";
            }).text(function(d) {
                return d.name;
            }).style("fill-opacity", 1e-6);

            // Transition nodes to their new position.
            var nodeUpdate = node.transition().duration(duration).attr("transform", function(d) {
                return "translate(" + d.y + "," + d.x + ")";
            });
            nodeUpdate.select("circle").attr("r", 4.5).style("fill", function(d) {
                return d._children ? "lightsteelblue" : "#fff";
            });
            nodeUpdate.select("text").style("fill-opacity", 1);

            // Transition exiting nodes to the parent's new position.
            var nodeExit = node.exit().transition().duration(duration).attr("transform", function(d) {
                return "translate(" + source.y + "," + source.x + ")";
            }).remove();
            nodeExit.select("circle").attr("r", 1e-6);
            nodeExit.select("text").style("fill-opacity", 1e-6);

            // Update the links…
            var link = svg.selectAll("path.link").data(links, function(d) {
                return d.target.id;
            });

            // Enter any new links at the parent's previous position.
            link.enter().insert("path", "g").attr("class", "link").attr("d", function(d) {
                var o = {
                    x: source.x0,
                    y: source.y0
                };
                return diagonal({
                    source: o,
                    target: o
                });
            });

            // Transition links to their new position.
            link.transition().duration(duration).attr("d", diagonal);

            // Transition exiting nodes to the parent's new position.
            link.exit().transition().duration(duration).attr("d", function(d) {
                var o = {
                    x: source.x,
                    y: source.y
                };
                return diagonal({
                    source: o,
                    target: o
                });
            }).remove();

            // Stash the old positions for transition.
            nodes.forEach(function(d) {
                d.x0 = d.x;
                d.y0 = d.y;
            });
        }

        // Toggle children on click.
        function click(d) {
            if (d.children) {
                d._children = d.children;
                d.children = null;
            } else {
                d.children = d._children;
                d._children = null;
            }
            update(d);
        }
    }

    function exportTreeToJSON(tree) {
        this._tree = tree;
        var manager = this;
        var json = '';
        renderBranch(null);
        json = '[' + json.substring(0, json.length - 1).replace(/\}\,\]/g, '}]');
        json += (json.slice(-1) === "]") ? '}]' : ']';

        function renderBranch(parentId) {
            for (var i = 0; i < manager._tree.length; i++) {
                if (manager._tree[i].parentId == parentId) {
                    json += JSON.stringify(manager._tree[i]);
                    // has children
                    if (findObjectByKey(manager._tree, "parentId", manager._tree[i].id)) {
                        json = json.substring(0, json.length - 1);
                        json += ', "children": [';
                        renderBranch(manager._tree[i].id);
                        json += ']}';
                    }
                    // has siblings
                    for (var n = 0; n < manager._tree.length; n++) {
                        if ((manager._tree[n] !== manager._tree[i]) && (manager._tree[n].parentId === manager._tree[i].parentId)) {
                            json += ',';
                            break;
                        }
                    }
                }
            }
        }
        return JSON.parse('{ "name" : "root","children": ' + json + '}');
    }

    function findObjectByKey(array, key, value) {
        for (var i = 0; i < array.length; i++) {
            if (array[i][key] === value) {
                return array[i];
            }
        }
        return null;
    }
</script>